package com.zhiyou100.context;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author yang
 * @className ClassPathXmlApplicationContext
 * @packageName com.zhiyou100.context
 * @Description TODO 解析 xml 文件
 * @date 2020-08-19 10:31
 */
public class ClassPathXmlApplicationContext {
    private String filename;
    /**
     * 记录整个 xml 文件
     */
    private ArrayList<Beans> beans;

    public ClassPathXmlApplicationContext() {
    }

    public ClassPathXmlApplicationContext(String filename) {
        this.filename = filename;
        init();
    }


    public Document getDocument(String name) {
        try {
            String ref = "src/main/resources/";
            return new SAXReader().read(ref + name);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }

    public Object getBean(String name) {

        if (getBeansById(name) == null) {
            // 没有找到
            throw new RuntimeException("不存在该 id");
        } else {
            // 找到了
            final Beans byId = getBeansById(name);
            try {
                // 获取 class 文件
                final Class<?> aClass = Class.forName(byId.getBean().getClassName());
                // 用无参数的构造方法，创建一个对象
                Object o = (aClass.newInstance());
                for (Property property : byId.getProperties()) {
                    // 读取参数名和参数值
                    final String propertyName = property.getName();
                    final String propertyValue = property.getValue();
                    // 根据根据参数名，获取字段
                    final Field field = ReflectUtil.getField(aClass, propertyName);
                    field.setAccessible(true);
                    // 给字段设置值
                    ReflectUtil.setFieldValue(o, field, Convert.convert(field.getType(), propertyValue));
                }
                // 回去此对象
                return o;
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("无法找到此类");
            } catch (IllegalAccessException | InstantiationException e) {
                throw new RuntimeException("没有无参数的构造方法");
            }
        }
    }

    public Beans getBeansById(String id) {
        Beans beans = null;

        for (Beans bean : this.beans) {
            if (bean.getBean().getId().equals(id)) {
                // 找到了，赋值，跳出
                beans = bean;
                break;
            }
        }

        return beans;
    }

    public void init() {
        // 读取 document 文档
        final Document document = getDocument(filename);
        // 读取所有的 bean 标签
        final List bean = document.getRootElement().elements("bean");
        // 创建一个 beans 记录所有的 bean
        final ArrayList<Beans> temp = new ArrayList<>();
        for (Object o : bean) {
            final Beans beans = new Beans();
            final Element element = (Element) (o);

            // 获取 class 和 ID
            final String aClass = element.attributeValue("class");
            final String id = element.attributeValue("id");
            // 设置 bean 参数
            beans.setBean(new Bean(aClass, id));

            final ArrayList<Property> properties = new ArrayList<>();
            for (Object property : element.elements("property")) {
                // 遍历所有的 property
                final Element property1 = (Element) (property);
                final String name = property1.attributeValue("name");
                final String value = property1.attributeValue("value");
                final Property property2 = new Property(name, value);
                properties.add(property2);
            }
            beans.setProperties(properties);
            temp.add(beans);
        }
        // 赋值
        this.beans = temp;
    }

    @Override
    public String toString() {
        return "ClassPathXmlApplicationContext{" +
                "filename='" + filename + '\'' +
                ", beans=" + beans +
                '}';
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public ArrayList<Beans> getBeans() {
        return beans;
    }

    public void setBeans(ArrayList<Beans> beans) {
        this.beans = beans;
    }
}

